<?php
/**
 * In this File the class '\UF\DateTime' is defined.
 *
 * @category   UniKap-Framework
 * @package    Core
 * @author     Ulf -UniKado- Kadner <ulfikado@gmail.com>
 * @since      2014-03-29 16:17
 * @version    0.1
 */

namespace UF
{

    # <editor-fold defaultstate="collapsed" desc="CLASS '\UF\DateTime'">

    /**
     * This class defines a object that represents a Datetime definition.
     * It encapsules a unix timestamp.
     *
     * The class uses, if usable, the {@link http://de1.php.net/intl INTL PHP extension} for date handling.
     *
     * If INTL is not usable, the normal PHP Date and time functions are used.
     *
     * @property int $Year The year of the current instance.
     * @property int $Month The month of the current instance.
     * @property int $Day The day of the current instance.
     * @property int $Hour The hour of the current instance.
     * @property int $Minute The minute of the current instance.
     * @property int $Second The second of the current instance.
     * @property-read int $Stamp Alias for 'Timestamp'
     * @property-read int $Timestamp The timestamp of the current instance.
     * @property-read \IAch\DateTime $Date The date, reduced to the time 00:00:00
     * @property-read int $DayOfYear The day of the year
     * @property-read bool $LeapYear Is current instance inside a leap year?
     * @property-read int $Quartal The quarter of the current instance.
     * @since  v0.1
     */
    class DateTime
        implements \UF\IStringConverter, \UF\IEquatable, \UF\IArrayConverter, \UF\IXmlConverter, \Serializable
    {

        # <editor-fold defaultstate="collapsed" desc="- - - -   P R I V A T E   F I E L D S   - - - - - - - - - - - - - - - - - - - - -">

        /**
         * @var    integer
         * @since  v0.1
         */
        private $unix_stamp;

        # </editor-fold>

        # <editor-fold defaultstate="collapsed" desc="- - - -   P R I V A T E   S T A T I C   F I E L D S   - - - - - - - - - - - - - -">

        /**
         * @var    array
         * @since  v0.1
         */
        private static $monthnamesDE = array( '', 'Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli',
                                              'August', 'September', 'Oktober', 'November', 'Dezember' );

        # </editor-fold>

        # <editor-fold defaultstate="collapsed" desc="- - - >   C O N S T R U C T O R   - - - - - - - - - - - - - - - - - - - - - - - -">

        /**
         * Inits a new instance. If no parameter is defined, the current timestamp is used.
         *
         * @param int $timestamp Unix-Timestamp or NULL for use the current timestamp.
         * @since  v0.1
         */
        public function __construct( $timestamp = null )
        {
            $this->unix_stamp = \is_integer($timestamp) ? $timestamp : \time();
        }

        # </editor-fold>

        # <editor-fold defaultstate="collapsed" desc="- - - -   G E T T E R S   - - - - - - - - - - - - - - - - - - - - - - - - - - - -">

        /**
         * Returns the current defined year (Length: 4)
         *
         * @return int
         * @since  v0.1
         */
        public final function getYear()
        {
            return \intval( \strftime( '%Y', $this->unix_stamp ) );
        }

        /**
         * Returns the current defined month (1-12)
         *
         * @return int
         * @since  v0.1
         */
        public final function getMonth()
        {
            return \intval( \strftime( '%m', $this->unix_stamp ) );
        }

        /**
         * Returns the current defined day of month (1-31)
         *
         * @return int
         * @since  v0.1
         */
        public final function getDay()
        {
            return \intval( \strftime( '%d', $this->unix_stamp ) );
        }

        /**
         * Returns the current defined hour (0-23)
         *
         * @return int
         * @since  v0.1
         */
        public final function getHour()
        {
            return \intval( \strftime( '%H', $this->unix_stamp ) );
        }

        /**
         * Returns the current defined minute (0-59)
         *
         * @return int
         * @since  v0.1
         */
        public final function getMinute()
        {
            return \intval( \strftime( '%M', $this->unix_stamp ) );
        }

        /**
         * Returns the current defined second (0-59)
         *
         * @return int Sekunde (0-59)
         * @since  v0.1
         */
        public final function getSecond()
        {
            return \intval( \strftime( '%S', $this->unix_stamp ) );
        }

        /**
         * Returns the current defined week day number (0-6)
         *
         * @return int
         * @since  v0.1
         */
        public final function getDayOfWeekNumber()
        {
            if ( \MOD_INTL ) {
                $fmt = \IntlDateFormatter::create(
                    (string) \UF\Locale::GetInstance(), \IntlDateFormatter::SHORT,
                    \IntlDateFormatter::SHORT, \date_default_timezone_get(),
                    \IntlDateFormatter::TRADITIONAL, 'e');
                return \intval( $fmt->format( $this->unix_stamp ) ); }
            if ( false === ($res = \strftime( '%u', $this->unix_stamp ) ) )
                $res = \strftime( '%w', $this->unix_stamp );
            return \intval( $res );
        }

        /**
         * Returns the current defined quarter of the year (1-4)
         *
         * @return int
         * @since  v0.1
         */
        public final function getQuartal()
        {
            if ( \MOD_INTL )
            {
                $fmt = \IntlDateFormatter::create(
                    (string) \UF\Locale::GetInstance(), \IntlDateFormatter::SHORT,
                    \IntlDateFormatter::SHORT, \date_default_timezone_get(),
                    \IntlDateFormatter::TRADITIONAL, 'Q');
                return \intval( $fmt->format( $this->unix_stamp ) );
            }
            $month = $this->getMonth();
            return ($month < 4) ? 1 : ($month < 7 ? 2 : ($month < 10 ? 3 : 4));
        }

        /**
         * Returns the current defined time zone offset (RFC822) (e.g.: -0800)
         *
         * @return string
         * @since  v0.1
         */
        public final function getTimezoneOffsetRFC822()
        {
            return \date( 'O', $this->unix_stamp );
        }

        /**
         * Returns the current defined time zone offset (to GMT) (e.g.: -08:00)
         *
         * @return string
         * @since  v0.1
         */
        public final function getTimezoneOffsetGMT()
        {
            return \date( 'P', $this->unix_stamp );
        }

        /**
         * Returns the name of the current defined time zone (e.g.: Europe/Berlin)
         *
         * @return string
         * @since  v0.1
         */
        public final function getTimezoneName()
        {
            return \date( 'e', $this->unix_stamp );
        }

        /**
         * Returns the abbreviated name of the current defined time zone (e.g.: CET)
         *
         * @return string
         * @since  v0.1
         */
        public final function getTimezoneNameShort()
        {
            return \date( 'T', $this->unix_stamp );
        }

        /**
         * Return if current instance points to a leap year.
         *
         * @return bool
         * @since  v0.1
         */
        public final function isLeapYear()
        {
            return (bool)\intval( \date( 'L', $this->unix_stamp ) );
        }

        /**
         * Returns, how many days the current year have.
         *
         * @return int 366 or 365
         * @since  v0.1
         */
        public final function getDaysOfYear()
        {
            return $this->isLeapYear() ? 366 : 365;
        }

        /**
         * Returns how many day the current month have.
         *
         * @return int
         * @since  v0.1
         */
        public final function getDaysOfMonth()
        {
            return \intval( \date( 't', $this->unix_stamp ) );
        }

        /**
         * Return the day of the year, for current instance.
         *
         * @return int
         * @since  v0.1
         */
        public final function getDayOfYear()
        {
            return \intval( \date( 'z', $this->unix_stamp ) );
        }

        /**
         * Returns the current date, reduced to the time 00:00:00 as a new {@see \UF\DateTime} instance.
         *
         * @return \UF\DateTime
         * @since  v0.1
         */
        public final function getDate()
        {
            return self::Create( $this->getYear, $this->getMonth, $this->getDay );
        }

        /**
         * Implements object cloning.
         *
         * @return \UF\DateTime
         * @since  v0.1
         */
        public function  __clone()
        {
            return new \UF\DateTime( $this->unix_stamp );
        }

        /**
         * Implements the magic getter for the use of dynamic class fields for read access.
         *
         * @param string $name
         * @return mixed
         * @since  v0.1
         */
        public function  __get( $name )
        {
            switch ( \strtolower($name ) )
            {
                case 'stamp': case 'timestamp': case 'unixtimestamp': case 'unix_timestamp':
                                  return $this->unix_stamp;
                case 'year':      return $this->getYear();
                case 'month':     return $this->getMonth();
                case 'day':       return $this->getDay();
                case 'hour':      return $this->getHour();
                case 'minute':    return $this->getMinute();
                case 'second':    return $this->getSecond();
                case 'date':      return $this->getDate();
                case 'dayofyear': return $this->getDayOfYear();
                case 'leapyear':  return $this->isLeapYear();
                case 'quartal': case 'quarter':
                                  return $this->getQuartal();
            }
            return false;
        }

        /**
         * Returns the next german holyday for defined state (Bundesland). All informations will be returned as array
         *
         * Array values of returned array are:
         *
         * - 0 (double) Difference days: The difference to next holyday, in days
         * - 1 (int) Time stamp: The unix time stamp of the next holyday
         * - 2(string) Name: The german name of the holyday
         *
         * @param int $state \UF\Bundesland (\UF\Bundesland::SACHSEN z.B.)
         * @return array
         * @since  v0.1
         */
        public final function getNextGermanHolyday( $state )
        {
            $ftage = \UF\Feiertage::AlleDeutschen( $state, $this->getYear() );
            $curr = array( 365, 0, null );
            foreach ( $ftage as $stamp => $name )
            {
                if ( $stamp < $this->unix_stamp ) continue;
                $curr = array(
                    ( $stamp - $this->unix_stamp ) / 86400,
                    $stamp,
                    $name
                );
                return $curr;
            }
            $stamp = \mktime( 0, 0, 0, 1, 1 , $this->year + 1 );
            $curr = array(
                ( $stamp - $this->unix_stamp ) / 86400,
                $stamp,
                'Neujahr'
            );
            return $curr;
        }

        /**
         * @return type
         * @since  v0.1
         */
        public final function getGermanMonthName()
        {
            return self::$monthnamesDE[$this->getMonth()];
        }

        # </editor-fold>

        # <editor-fold defaultstate="collapsed" desc="- - - -   S E T T E R S   - - - - - - - - - - - - - - - - - - - - - - - - - - - -">

        /**
         * Sets a new time for current date and returns it as a new instance.
         *
         * @param  int $hour   The new hour value (Default to 0)
         * @param  int $minute The new minute value (Default to 0)
         * @param  int $second The new second value (Default to 0)
         * @return \UF\DateTime
         * @since  v0.1
         */
        public final function setTime( $hour = 0, $minute = 0, $second = 0 )
        {
            if ( \is_null( $hour ) )   $hour = $this->getHour();
            if ( \is_null( $minute ) ) $minute = $this->getMinute();
            if ( \is_null( $second ) ) $second = $this->getSecond();
            return new \UF\DateTime( \mktime(
                $hour, $minute, $second, $this->getMonth(), $this->getDay(), $this->getYear() ) );
        }

        /**
         * Sets a new time for current date internal.
         *
         * @param  int $hour   The new hour value (Default to 0)
         * @param  int $minute The new minute value (Default to 0)
         * @param  int $second The new second value (Default to 0)
         * @since  v0.1
         */
        public final function setTimeInternal( $hour = 0, $minute = 0, $second = 0 )
        {
            if ( \is_null( $hour ) )   $hour = $this->getHour();
            if ( \is_null( $minute ) ) $minute = $this->getMinute();
            if ( \is_null( $second ) ) $second = $this->getSecond();
            $this->unix_stamp = \mktime(
                $hour, $minute, $second, $this->getMonth(), $this->getDay(), $this->getYear());
        }

        /**
         * Sets a new Date with the current time and returns it as a new instance.
         *
         * @param  int $year  The new year (if NULL, the origin year will be used)
         * @param  int $month The new month (if NULL, the origin month will be used)
         * @param  int $day   The new day (if NULL, the origin day will be used)
         * @return \UF\DateTime
         * @since  v0.1
         */
        public final function setDate( $year=null, $month=null, $day=null )
        {
            if ( \is_null( $year ) )  $year = $this->getYear();
            if ( \is_null( $month ) ) $month = $this->getMonth();
            if ( \is_null( $day ) )   $day = $this->getDay();
            return new \UF\DateTime( \mktime(
                $this->getHour(), $this->getMinute(), $this->getSecond(), $month, $day, $year ) );
        }

        /**
         * Sets a new Date with the current time internal.
         *
         * @param  int $year  The new year (if NULL, the origin year will be used)
         * @param  int $month The new month (if NULL, the origin month will be used)
         * @param  int $day   The new day (if NULL, the origin day will be used)
         * @since  v0.1
         */
        public final function setDateInternal( $year=null, $month=null, $day=null )
        {
            if ( \is_null( $year ) )  $year = $this->getYear();
            if ( \is_null( $month ) ) $month = $this->getMonth();
            if ( \is_null( $day ) )   $day = $this->getDay();
            $this->unix_stamp = \mktime(
                $this->getHour(), $this->getMinute(), $this->getSecond(), $month, $day, $year );
        }

        /**
         * Sets a new year and returns the result as a new \UF\DateTime instance.
         * If no value is defined (also if NULL) so the current actual year is used.
         *
         * @param int|null $year The new year value
         * @return \UF\DateTime
         * @since  v0.1
         */
        public final function setYear( $year=null )
        {
            if ( \is_null( $year ) ) $year = self::CurrentYear();
            return new \UF\DateTime( \mktime(
                $this->getHour(), $this->getMinute(), $this->getSecond(), $this->getMonth(), $this->getDay(), $year ) );
        }

        /**
         * Sets a new year internal. If no value is defined (also if NULL) so the current actual year is used.
         *
         * @param int|null $year The new year value
         * @since  v0.1
         */
        public final function setYearInternal( $year=null )
        {
            if ( \is_null( $year ) ) $year = self::CurrentYear();
            $this->unix_stamp = \mktime(
                $this->getHour(), $this->getMinute(), $this->getSecond(), $this->getMonth(), $this->getDay(), $year );
        }

        /**
         * Sets a new month and returns the result as a new \UF\DateTime instance.
         * If no value is defined (also if NULL) so the current actual month is used.
         *
         * @param int|null $month The new month value
         * @return \UF\DateTime
         * @since  v0.1
         */
        public final function setMonth( $month=null )
        {
            if ( \is_null( $month ) ) $month = self::CurrentMonth();
            return new \UF\DateTime( \mktime(
                $this->getHour(), $this->getMinute(), $this->getSecond(), $month, $this->getDay(), $this->getYear() ) );
        }

        /**
         * Sets a new month internal. If no value is defined (also if NULL) so the current actual month is used.
         *
         * @param int|null $month The new month value
         * @since  v0.1
         */
        public final function setMonthInternal( $month=null )
        {
            if ( \is_null( $month ) ) $month = self::CurrentMonth();
            $this->unix_stamp = \mktime(
                $this->getHour(), $this->getMinute(), $this->getSecond(), $month, $this->getDay(), $this->getYear() );
        }

        /**
         * Sets a new day and returns the result as a new \UF\DateTime instance.
         * If no value is defined (also if NULL) so the current actual day is used.
         *
         * @param int|null $day The new day value
         * @return \UF\DateTime
         * @since  v0.1
         */
        public final function setDay( $day=null )
        {
            if ( \is_null( $day ) ) $day = self::CurrentDay();
            return new \UF\DateTime( \mktime(
                $this->getHour(), $this->getMinute(), $this->getSecond(), $this->getMonth(), $day, $this->getYear() ) );
        }

        /**
         * Sets a new day internal. If no value is defined (also if NULL) so the current actual day is used.
         *
         * @param int|null $day The new day value
         * @since  v0.1
         */
        public final function setDayInternal( $day=null )
        {
            if ( \is_null( $day ) ) $day = self::CurrentDay();
            $this->unix_stamp = \mktime(
                $this->getHour(), $this->getMinute(), $this->getSecond(), $this->getMonth(), $day, $this->getYear() );
        }

        /**
         * Overrides the magic setter.
         *
         * @param string $name
         * @param mixed $value
         * @since  v0.1
         */
        public function  __set( $name, $value )
        {
            switch ( \strtolower($name ) )
            {
                case 'year':     $this->setYearInternal( $value );              break;
                case 'month':    $this->setMonthInternal( $value );             break;
                case 'day':      $this->setDayInternal( $value );               break;
                case 'hour':     $this->setTimeInternal( $value, null, null );  break;
                case 'minute':   $this->setTimeInternal( null, $value, null );  break;
                case 'second':   $this->setTimeInternal( null, null, $value );  break;
                default:                                                        break;
            }
        }

        # </editor-fold>

        # <editor-fold defaultstate="collapsed" desc="- - - -   P U B L I C   M E T H O D S   - - - - - - - - - - - - - - - - - - - - -">

        # <editor-fold defaultstate="collapsed" desc="P U B L I C   A D D   M E T H O D S">

        /**
         * Adds seconds and return the result as a new \UF\DateTime instance.
         *
         * @param  int $seconds The seconds to add (positive or negative)
         * @return \UF\DateTime
         * @since  v0.1
         */
        public final function addSeconds( $seconds=1 )
        {
            $plus = $seconds > -1 ? '+' : '';
            $name = (($seconds > 1) || ($seconds < -1)) ? ' seconds' : ' second';
            return new \UF\DateTime( \strtotime($plus . $seconds . $name,  $this->unix_stamp ) );
        }

        /**
         * Adds seconds internal
         *
         * @param  int $seconds The seconds to add (positive or negative)
         * @since  v0.1
         */
        public final function addSecondsInternal( $seconds=1 )
        {
            $plus = $seconds > -1 ? '+' : '';
            $name = (($seconds > 1) || ($seconds < -1)) ? ' seconds' : ' second';
            $this->unix_stamp = \strtotime( $plus . $seconds . $name,  $this->unix_stamp );
        }

        /**
         * Adds minutes and return the result as a new \UF\DateTime instance.
         *
         * @param  int $minutes The minutes to add (positive or negative)
         * @return \UF\DateTime
         * @since  v0.1
         */
        public final function addMinutes( $minutes=1 )
        {
            $plus = $minutes > -1 ? '+' : '';
            $name = (($minutes > 1) || ($minutes < -1)) ? ' minutes' : ' minute';
            return new \UF\DateTime( \strtotime($plus . $minutes . $name,  $this->unix_stamp ) );
        }

        /**
         * Adds minutes internal
         *
         * @param  int $minutes The minutes to add (positive or negative)
         * @since  v0.1
         */
        public final function addMinutesInternal( $minutes=1 )
        {
            $plus = $minutes > -1 ? '+' : '';
            $name = (($minutes > 1) || ($minutes < -1)) ? ' minutes' : ' minute';
            $this->unix_stamp = \strtotime( $plus . $minutes . $name,  $this->unix_stamp );
        }

        /**
         * Adds hours and return the result as a new \UF\DateTime instance.
         *
         * @param  int $hours The hours to add (positive or negative)
         * @return \UF\DateTime
         * @since  v0.1
         */
        public final function addHours( $hours=1 )
        {
            $plus = $hours > -1 ? '+' : '';
            $name = (($hours > 1) || ($hours < -1)) ? ' hours' : ' hour';
            return new \UF\DateTime( \strtotime($plus . $hours . $name,  $this->unix_stamp ) );
        }

        /**
         * Adds hours internal
         *
         * @param  int $hours The hours to add (positive or negative)
         * @since  v0.1
         */
        public final function addHoursInternal( $hours=1 )
        {
            $plus = $hours > -1 ? '+' : '';
            $name = (($hours > 1) || ($hours < -1)) ? ' hours' : ' hour';
            $this->unix_stamp = \strtotime( $plus . $hours . $name,  $this->unix_stamp );
        }

        /**
         * Adds days and return the result as a new \UF\DateTime instance.
         *
         * @param  int $days The days to add (positive or negative)
         * @return \UF\DateTime
         * @since  v0.1
         */
        public final function addDays( $days=1 )
        {
            $plus = $days > -1 ? '+' : '';
            $name = (($days > 1) || ($days < -1)) ? ' days' : ' day';
            return new \UF\DateTime( \strtotime($plus . $days . $name,  $this->unix_stamp ) );
        }

        /**
         * Adds days internal
         *
         * @param  int $days The days to add (positive or negative)
         * @since  v0.1
         */
        public final function addDaysInternal( $days=1 )
        {
            $plus = $days > -1 ? '+' : '';
            $name = (($days > 1) || ($days < -1)) ? ' days' : ' day';
            $this->unix_stamp = \strtotime( $plus . $days . $name,  $this->unix_stamp );
        }

        /**
         * Adds weeks and return the result as a new \UF\DateTime instance.
         *
         * @param  int $weeks The weeks to add (positive or negative)
         * @return \UF\DateTime
         * @since  v0.1
         */
        public final function addWeeks( $weeks=1 )
        {
            $plus = $weeks > -1 ? '+' : '';
            $name = (($weeks > 1) || ($weeks < -1)) ? ' weeks' : ' week';
            return new \UF\DateTime( \strtotime($plus . $weeks . $name,  $this->unix_stamp ) );
        }

        /**
         * Adds weeks internal
         *
         * @param  int $weeks The weeks to add (positive or negative)
         * @since  v0.1
         */
        public final function addWeeksInternal( $weeks=1 )
        {
            $plus = $weeks > -1 ? '+' : '';
            $name = (($weeks > 1) || ($weeks < -1)) ? ' weeks' : ' week';
            $this->unix_stamp = \strtotime( $plus . $weeks . $name,  $this->unix_stamp );
        }

        /**
         * Moves the current time to the end of the day (23:59:59) and returs it as a new \UF\DateTime instance.
         *
         * @return \UF\DateTime
         * @since  v0.1
         */
        public final function moveToEndOfDay()
        {
            return $this->setTime( 23, 59, 59 );
        }

        /**
         * Moves the current time to the end of the day (23:59:59) internal
         *
         * @since  v0.1
         */
        public final function moveToEndOfDayInternal()
        {
            return $this->setTimeInternal( 23, 59, 59 );
        }

        # </editor-fold>

        # <editor-fold defaultstate="collapsed" desc="P U B L I C   F O R M A T   M E T H O D S">

        /**
         * Formats the current datetime for use in databases (eg. MySQL) for example <code>2001-12-24 00:00:00</code>
         *
         * @return string
         * @since  v0.1
         */
        public final function formatMysqlDateTime()
        {
            return \strftime( '%Y-%m-%d %H:%M:%S', $this->unix_stamp );
        }

        /**
         * Formats the current date for use in databases (eg. MySQL) for example <code>2001-12-24</code>
         *
         * @return string
         * @since  v0.1
         */
        public final function formatMysqlDate()
        {
            return \strftime( '%Y-%m-%d', $this->unix_stamp );
        }

        /**
         * Formats date, with using names for weekday and month e.g.: <code>Montag, 20. Dezember 2030</code>
         * or <code>Mon, 20. Dec 2030</code>
         *
         * @param  bool $short Use short names
         * @return string
         * @since  v0.1
         */
        public final function formatNamedDate( $short=false )
        {
            if ( \MOD_INTL )
            {
                if ( $short ) $fmt = \IntlDateFormatter::create(
                    (string) \UF\Locale::GetInstance(), 3, 3, \date_default_timezone_get(), 0, 'E, d. MMM y');
                else $fmt = \IntlDateFormatter::create(
                    (string) \UF\Locale::GetInstance(), 3, 3, \date_default_timezone_get(), 0, 'EEEE, d. MMMM y');
                return $fmt->format( $this->unix_stamp );
            }
            if ( $short ) $fmt = '%a, %d. %b %Y';
            else $fmt = '%A, %d. %B %Y';
            return \strftime( $fmt, $this->unix_stamp );
        }

        /**
         * Formats datetime, with using names for weekday and month e.g.: <code>Montag, 20. Dezember 2030 14:22:04</code>
         * or <code>Mon, 20. Dec 2030 14:22:04</code>
         *
         * @param  bool $short Use short names
         * @return string
         * @since  v0.1
         */
        public final function formatNamedDateTime( $short=false )
        {
            if ( \MOD_INTL )
            {
                if ( $short ) $fmt = \IntlDateFormatter::create(
                    (string) \UF\Locale::GetInstance(), 3, 3, \date_default_timezone_get(), 0, 'E, d. MMM y HH:mm' );
                else $fmt = \IntlDateFormatter::create(
                    (string) \UF\Locale::GetInstance(), 3, 3, \date_default_timezone_get(), 0,
                    'EEEE, d. MMMM y HH:mm:ss');
                return $fmt->format( $this->unix_stamp );
            }
            if ( $short )
                if ( 'de' === \UF\Locale::GetInstance()->getLID() ) $fmt = '%a der %d. %b %Y %H:%M';
                else $fmt = '%a, %d. %b %Y %H:%M';
            else
                if ( 'de' === \UF\Locale::GetInstance()->getLID() ) $fmt = '%A der %d. %B %Y %H:%M:%S';
                else $fmt = '%A, %d. %B %Y %H:%M:%S';
            return \strftime( $fmt, $this->unix_stamp );
        }

        /**
         * Formats datetime compatible with RFC 2822. (e.g.: <code>Thu, 21 Dec 2000 16:01:07 +0200</code>)
         *
         * @return string
         * @since  v0.1
         */
        public final function formatRfc()
        {
            return \date( 'D, d M Y H:i:s O', $this->unix_stamp );
        }

        /**
         * Formats datetime compatible with W3C (e.g.: <code>2009-02-27T21:47:11+01:00</code>)
         *
         * @return string
         * @since  v0.1
         */
        public final function formatW3C()
        {
            return \strftime( '%Y-%m-%dT%H:%M:%S', $this->unix_stamp ) . \date( 'P', $this->unix_stamp );
        }

        /**
         * Formats datetime with \strftime().
         *
         * @param  string $format e.g.: %Y-%m-%d %H:%M:%S
         * @return string
         * @since  v0.1
         */
        public final function formatWithStrftime( $format )
        {
            if ( \MOD_INTL )
            {
                $format = self::convertStrftimeFormatToIntl( $format );
                $fmt = \IntlDateFormatter::create(
                    (string) \UF\Locale::GetInstance(), 3, 3, \date_default_timezone_get(), 0, $format );
                $result = $fmt->format( $this->unix_stamp );
                if ( !\UF\str_contains( $result, '%\\' ) ) return $result;
                $result = \preg_replace( '~%\\([A-Za-z])~', '%$1', $result );
                return \strftime( $result, $this->unix_stamp );
            }
            return \strftime( $format, $this->unix_stamp );
        }

        /**
         * Formats datetime with \date()
         *
         * @param  string $format
         * @return string
         * @since  v0.1
         */
        public final function formatWithDate( $format )
        {
            return \date( $format, $this->unix_stamp );
        }

        # </editor-fold>

        # <editor-fold defaultstate="collapsed" desc=" I N T E R F A C E   I M P L E N T A T I O N S ">

        # <editor-fold defaultstate="collapsed" desc="Implement \Serializable">

        /**
         * Serialize the element to a string.
         *
         * @return string
         * @since  v0.1
         */
        public function serialize()
        {
            return \serialize( $this->formatW3C() );
        }
        /**
         * @since  v0.1
         */
        public function unserialize( $serialized )
        {
            $this->fromString( \unserialize( $serialized ) );
        }

        # </editor-fold>

        # <editor-fold defaultstate="collapsed" desc="Implement \UF\IStringConverter">

        /**
         * Overrides the magic _toString Method for casting instance to string.
         *
         * @return string
         * @since  v0.1
         */
        public function __toString()
        {
            return $this->toString();
        }

        /**
         * Returns the string, associated with the datetime.
         *
         * @return string
         * @since  v0.1
         */
        public function toString()
        {
            if ( \MOD_INTL )
            {
                $fmt = \IntlDateFormatter::create(
                    (string) \UF\Locale::GetInstance(), \IntlDateFormatter::SHORT,
                    \IntlDateFormatter::SHORT, \date_default_timezone_get(),
                    \IntlDateFormatter::TRADITIONAL, 'y-MM-dd HH:mm:ss ZZZZ');
                return $fmt->format( $this->unix_stamp );
            }
            return $this->formatMysqlDateTime();
        }

        /**
         * Changes the current timestamp to the value, defined by $objectString.
         *
         * @param  string $objectString String that defines a date(time).
         * @return bool
         * @since  v0.1
         */
        public function fromString( $objectString )
        {
            if ( false !== ( $stp = \strtotime( $objectString, $this->unix_stamp ) ) )
            {
                if ( 0 < $stp ) {
                    $this->unix_stamp = $stp;
                    return true; }
            }
            $search =
                '~(Mon?|Monday|Montag|Tue|Di|Tuesday|Dienstag|Wed|Mi|Wednesd' .
                'ay|Mittwoch|Thu|Do|Thusday|Donnerstag|Fri?|Friday|Freitag|S' .
                'at?|Saturday|Samstag|Sonnabend|Sun|So|Sunday|Sonntag)\b~i';
            $objectString = \preg_replace( $search, '', $objectString );
            if ( false !== ( $stp = \strtotime( $objectString, $this->unix_stamp ) ) )
            {
                if ( 0 < $stp ) {
                    $this->unix_stamp = $stp;
                    return true; }
            }
            return false;
        }

        # </editor-fold>

        # <editor-fold defaultstate="collapsed" desc="Implement \UF\IEquatable">

        /**
         * Equals the current instance with the defined $value.
         *
         * If the 2. parameter is TRUE is requires that $value must be of type \UF\DateTime for a paoitive result.
         *
         * @param  mixed $value  THe value to compare with
         * @param  bool  $strict Check strictly?
         * @return bool  TRUE on succes, FALSE otherwise.
         * @since  v0.1
         */
        public function equals( $value, $strict=false )
        {
            if ( $value instanceof \UF\DateTime ) return $value->unix_stamp == $this->unix_stamp;
            if ( $strict ) return false;
            if ( \is_integer( $value ) ) return $value == $this->unix_stamp;
            if ( !\is_string( $value ) ) return false;
            if ( false === ( $dt = self::Parse( $value ) ) ) return false;
            return $dt->unix_stamp == $this->unix_stamp;
        }

        # </editor-fold>

        # <editor-fold defaultstate="collapsed" desc="Implement \UF\IArrayConverter">

        /**
         * Changes the timestamp of current instance to the timestamp from $objectData['stamp'].
         *
         * @param  array $objectData Associative Array
         * @return bool
         * @since  v0.1
         */
        public function fromArray( array $objectData )
        {
            if ( !isset ( $objectData['stamp'] ) ) return false;
            $this->unix_stamp = \intval( $objectData['stamp'] );
            return true;
        }

        /**
         * Returns all instancedata as a associative array. Contained array keys are 'stamp', 'year', 'month', 'day',
         * 'hour', 'minute' and 'second'
         *
         * @return array Associative Array
         * @since  v0.1
         */
        public function toArray()
        {
            return array(
                'stamp'  => $this->unix_stamp,
                'year'   => $this->getYear(),
                'month'  => $this->getMonth(),
                'day'    => $this->getDay(),
                'hour'   => $this->getHour(),
                'minute' => $this->getMinute(),
                'second' => $this->getSecond()
            );
        }

        # </editor-fold>

        # <editor-fold defaultstate="collapsed" desc="Implement \UF\IXmlConverter">

        /**
         * Writes all instancedata to the defined XmlWriter. Default Element name is 'DateTime'. Is uses the attribute
         * 'timestamp'. Thats all.
         *
         * @param  \XmlWriter $w The XmlWriter
         * @param  string $elementName The Name of the element to create (Defaults to 'DateTime')
         * @since  v0.1
         */
        public function writeXML( \XmlWriter $w, $elementName = 'DateTime' )
        {
            $w->startElement( $elementName );
            $this->writeXMLAttribute( $w );
            $w->endElement();
        }

        /**
         * Reads the timestamp from defined XML element. It can be defined by one of the following attributes:
         * 'timestamp', 'datetime' or 'value', or it is defined as element string.
         *
         * The value it self can be a integer (Timestamp) or a datetime string.
         *
         * @param  \SimpleXMLElement $xmlElement
         * @return boolean
         * @since  v0.1
         */
        public function readXML( \SimpleXMLElement $xmlElement )
        {
            if ( isset( $xmlElement['timestamp'] ) )    $str = (string) $xmlElement['timestamp'];
            elseif ( isset( $xmlElement['datetime'] ) ) $str = (string) $xmlElement['datetime'];
            elseif ( isset( $xmlElement['value'] ) )    $str = (string) $xmlElement['value'];
            else                                        $str = (string) $xmlElement;
            if ( \UF\TypeTool::IsInteger( $str ) )
            {
                $this->unix_stamp = \intval( $str );
                return true;
            }
            return $this->fromString( $str );
        }

        # </editor-fold>

        # </editor-fold>

        /**
         * Compares the curren DateTime with the defined and returns <b>-1</b> if $value is bigger than current,
         * <b>0</b> if both are equal or <b>1</b> if current is bigger than $value.
         *
         * @param  mixed $value Value to compare with
         * @return int -1, 0, 1 or (bool)FALSE if comparison isnt usable
         * @since  v0.1
         */
        public function compare( $value )
        {
            if ( $value instanceof \UF\DateTime ) return ( ( $value->unix_stamp > $this->unix_stamp )
                ? -1 : ( ( $value->unix_stamp < $this->unix_stamp ) ? 1 : 0 ) );
            if ( \is_integer( $value ) ) return ( ( $value > $this->unix_stamp )
                ? -1 : ( ( $value < $this->unix_stamp ) ? 1 : 0 ) );
            if ( \is_string( $value ) )
            {
                if ( false === ( $dt = self::Parse( $value ) ) ) return false;
                return ( ( $dt->unix_stamp > $this->unix_stamp )
                    ? -1 : ( ( $dt->unix_stamp < $this->unix_stamp ) ? 1 : 0 ) );
            }
            return false;
        }

        /**
         * Writes the timestamp of the object to a xml attribute
         *
         * @param  \XmlWriter $w THe XmlWrite to write the attribute
         * @param  type $attributeName The name of the XML attribute (Defaults to 'timestamp')
         * @since  v0.1
         */
        public function writeXMLAttributes( \XmlWriter $w, $attributeName = 'timestamp' )
        {
            $w->writeAttribute($attributeName, $this->unix_stamp);
        }

        # </editor-fold>

        # <editor-fold defaultstate="collapsed" desc="- - - -   P U B L I C   S T A T I C   M E T H O D S   - - - - - - - - - - - - - -">

        /**
         * Parses a Datetime string to a {@see \UF\DateTime} instance.
         *
         * @param  string $datetimestring
         * @return \UF\DateTime Or boolean FALSE
         * @since  v0.1
         */
        public static function Parse( $datetimestring )
        {
            if ( $datetimestring instanceof \UF\DateTime) return $datetimestring;
            if ( !\is_string( $datetimestring ) ) $datetimestring = \strval( $datetimestring );
            $dt = new \UF\DateTime();
            if ( !$dt->fromString( $datetimestring ) ) return false;
            return $dt;
        }

        /**
         * Returns, how many days the defined month of the defined year has.
         *
         * @return int
         * @since  v0.1
         */
        public static function GetDaysInMonth( $year, $month )
        {
            $stamp = \mktime( 0, 0, 0, $month, 2, $year );
            return \intval( \date( 't', $stamp ) );
        }

        /**
         * Inits a new instance from the defined data.
         *
         * @param  int $year The year (4 digits)
         * @param  int $month The month (1-12)
         * @param  int $day The day (1-31)
         * @param  int $hour The hour (0-23) (Defaults to 0)
         * @param  int $minute The minute (0-59) (Defaults to 0)
         * @param  int $second The second (0-59) (Defaults to 0)
         * @return \UF\DateTime
         * @since  v0.1
         */
        public static function Create( $year, $month, $day, $hour=0, $minute=0, $second=0 )
        {
            return new \UF\DateTime( \mktime( $hour, $minute, $second, $month, $day, $year ) );
        }

        /**
         * Returns the current year.
         *
         * @return int
         * @since  v0.1
         */
        public static function CurrentYear()
        {
            return \intval( \strftime( '%Y' ) );
        }

        /**
         * Returns the current month.
         *
         * @return int
         * @since  v0.1
         */
        public static function CurrentMonth()
        {
            return \intval( \strftime( '%m' ) );
        }

        /**
         * Returns the current day of month
         *
         * @return int
         * @since  v0.1
         */
        public static function CurrentDay()
        {
            return \intval( \strftime( '%d' ) );
        }

        /**
         * Returns a new DateTime instance for now.
         *
         * @return \UF\DateTime
         * @since  v0.1
         */
        public static function Now()
        {
            return new \UF\DateTime();
        }

        /**
         * Returns the DateTime of the last modification for a file.
         *
         * @param  string $file
         * @return \UF\DateTime
         * @since  v0.1
         */
        public static function FromFile( $file )
        {
            return new \UF\DateTime( \filemtime( $file ) );
        }

        # </editor-fold>

        # <editor-fold defaultstate="collapsed" desc="- - - -   P R I V A T E   S T A T I C   M E T H O D S   - - - - - - - - - - - - -">

        /**
         * @param  string $format
         * @return string
         * @since  v0.1
         */
        private static function convertStrftimeFormatToIntl( $format )
        {
            $replace = array(
                '%C' => 'G',        '%Y' => 'y',        '%y' => 'yy',       '%m' => 'MM',       '%b' => 'MMM',
                '%h' => 'MMM',      '%B' => 'MMMM',     '%d' => 'dd',       '%j' => 'D',        '%a' => 'E',
                '%A' => 'EEEE',     '%u' => 'e',        '%p' => 'a',        '%I' => 'hh',       '%H' => 'HH',
                '%M' => 'mm',       '%S' => 'ss',       '%z' => 'zzzz',     '%Z' => 'zzzz',     '%c' => '%\\c',
                '%D' => 'MM/dd/yy', '%e' => '%\\e',     '%n' => "\n",       '%t' => "\t",       '%r' => 'hh:mm:ss a',
                '%R' => 'HH:mm:ss', '%T' => 'HH:mm:ss', '%U' => 'w',        '%V' => 'w',        '%W' => 'w',
                '%w' => '%\\w',     '%x' => '%\\x',     '%X' => '%\\X',     '%%' => '%' );
            $resultStr = '';
            $flen = \strlen( $format );
            for ( $i = 0; $i < $flen; ++$i )
            {
                if ( '%' !== $format[$i] ) {
                    $resultStr .= $format[$i];
                    continue; }
                if ( $i + 1 >= $flen ) {
                    $resultStr .= $format[$i];
                    continue; }
                $key = \substr( $format, $i, 2 );
                ++$i;
                if ( isset ( $replace[$key] ) ) $resultStr .= $replace[$key];
                else $resultStr .= $key;
            }
            return $resultStr;
        }

        # </editor-fold>

    }

    # </editor-fold>

    # <editor-fold defaultstate="collapsed" desc="CLASS '\UF\Bundesland">

    /**
     * Diese Klasse stellt ausschliesslich Konstanten bereit, die alle deutschen
     * Bundeslaender definieren.
     *
     * @category   OpenSoftstepsFramework
     * @package    Core
     * @subpackage Helpers
     * @author     Ulf [Kado] Kadner <ulf@softsteps.de>
     * @since      29.10.2010 16:20:56
     * @version    2.0.0
     */
    class Bundesland
    {

        private function __construct() { }

        # <editor-fold defaultstate="collapsed" desc="C O N S A N T S">

        const BADENWUETENBERG = 0;
        const BAYERN = 1;
        const BERLIN = 2;
        const BRANDENBURG = 3;
        const BREMEN = 2;
        const HAMBURG = 2;
        const HESSEN = 6;
        const MECKLENBURG_VORPOMMERN = 3;
        const NIEDERSACHSEN = 2;
        const NORDREIHN_WESTFALEN = 9;
        const RHEINLAND_PFALZ = 9;
        const SAARLAND = 11;
        const SACHSEN = 12;
        const SACHSEN_ANHALT = 13;
        const SCHLESWIG_HOLSTEIN = 2;
        const THUERINGEN = 15;

        # </editor-fold>

    }

    # </editor-fold>

    # <editor-fold defaultstate="collapsed" desc="CLASS '\UF\Feiertage">

    /**
     * Eine Klasse mit statischen Funktionen, die der Ermittlung von Feiertagen dient.
     *
     * @category   OpenSoftstepsFramework
     * @package    Core
     * @subpackage Helpers
     * @author     Ulf [Kado] Kadner <ulf@softsteps.de>
     * @since      29.10.2010 16:20:56
     * @version    2.0.0
     */
    class Feiertage
    {

        private function __construct() { }

        # <editor-fold defaultstate="collapsed" desc="P U B L I C   S T A T I C   M E T H O D S">

        /**
         * Gibt den Unix Timestamp zurueck, der auf den Tag zeigt auf den der
         * Ostersonntag im angegebenen Jahr faellt. Wird kein Jahr angegeben, so
         * wird das aktuelle Jahr genutzt.
         *
         * Die Berechnung des Ostersonntags erfolgt dabei nach der
         * "Gausschen Gleichung".
         *
         * @param int $jahr Optionale angabe fuers Jahr (4-stellig)
         * @return int Unix-Timestamp fuer Ostersonntag
         */
        public static function OsterSonntag( $jahr=null )
        {
            if (empty($jahr)) $jahr = \intval( \strftime('%Y') );
            $a = $jahr % 19;
            $b = $jahr % 4;
            $c = $jahr % 7;
            $m = \number_format(
                8 * \number_format($jahr/100) + 13
            ) / 25 - 2;
            $s = \number_format($jahr/100) - \number_format($jahr/400) - 2;
            $M = (15 + $s - $m) % 30;
            $N = (6 + $s) % 7;
            $d = ($M + 19 * $a) % 30;
            $D = 28;
            if ($d != 29)
            {
                if ($d == 28 && $a >= 11) $D = 27;
                else $D = $d;
            }
            $e = (2 * $b + 4 * $c + 6 * $D + $N) % 7;
            return \mktime (0, 0, 0, 3, 21, $jahr) + (($D + $e + 1) * 86400);
        }

        /**
         * Gibt alle Feiertage fuer das angegebene Bundesland und das angebene Jahr
         * zurueck. Wird kein Jahr angegeben so wird das aktuelle Jahr genutzt.
         *
         * Als Wert fuers Bundesland wird eine der Konstanten erwartet die in der
         * Klasse {@see \UF\Bundesland} definiert wurden.
         *
         * @param  int $bundesland Siehe Konstenten aus {@see \UF\Bundesland}
         * @param  int $jahr
         * @return array Key ist der Timestamp, Value ist der Feitertagsname.
         */
        public static function AlleDeutschen( $bundesland, $jahr=null )
        {
            if ( empty($jahr) ) $jahr = \intval( \strftime( '%Y' ) );
            $ostern = self::OsterSonntag( $jahr );
            $res = array(
                \mktime( 0, 0, 0, 1, 1, $jahr )   => 'Neujahr',
                ( $ostern - 172800 )              => 'Karfreitag',
                $ostern                           => 'Ostersonntag',
                ( $ostern + 86400 )               => 'Ostermontag',
                \mktime( 0, 0, 0, 5, 1, $jahr )   => 'Tag der Arbeit',
                \mktime( 0, 0, 0, 10, 3, $jahr )  => 'Tag der deutschen Einheit',
                \mktime( 0, 0, 0, 12, 25, $jahr ) => '1. Weihnachtstag',
                \mktime( 0, 0, 0, 12, 26, $jahr ) => '2. Weihnachtstag'
            );
            switch ( $bundesland )
            {
                case \UF\Bundesland::BADENWUETENBERG:
                    $res[\mktime(0,0,0,1,6,$jahr)] = 'Heilige Drei Koenige';
                    $res[\mktime(0,0,0,5,22,$jahr)] = 'Fronleichnam';
                    $res[\mktime(0,0,0,11,1,$jahr)] = 'Allerheiligen';
                    return $res;
                case \UF\Bundesland::BAYERN:
                    $res[\mktime(0,0,0,1,6,$jahr)] = 'Heilige Drei Koenige';
                    $res[\mktime(0,0,0,5,22,$jahr)] = 'Fronleichnam';
                    $res[\mktime(0,0,0,8,15,$jahr)] = 'Mariae Himmelfahrt';
                    $res[\mktime(0,0,0,11,1,$jahr)] = 'Allerheiligen';
                    return $res;
                case \UF\Bundesland::BERLIN:
                    return $res;
                case \UF\Bundesland::BRANDENBURG:
                    $res[\mktime(0,0,0,10,31,$jahr)] = 'Reformationsfest';
                    return $res;
                case \UF\Bundesland::HESSEN:
                    $res[\mktime(0,0,0,5,22,$jahr)] = 'Fronleichnam';
                    return $res;
                case \UF\Bundesland::NORDREIHN_WESTFALEN:
                    $res[\mktime(0,0,0,5,22,$jahr)] = 'Fronleichnam';
                    $res[\mktime(0,0,0,11,1,$jahr)] = 'Allerheiligen';
                    return $res;
                case \UF\Bundesland::SAARLAND:
                    $res[\mktime(0,0,0,5,22,$jahr)] = 'Fronleichnam';
                    $res[\mktime(0,0,0,8,15,$jahr)] = 'Mariae Himmelfahrt';
                    $res[\mktime(0,0,0,11,1,$jahr)] = 'Allerheiligen';
                    return $res;
                case \UF\Bundesland::SACHSEN:
                    $res[\mktime(0,0,0,5,22,$jahr)] = 'Fronleichnam';
                    $res[\mktime(0,0,0,10,31,$jahr)] = 'Reformationsfest';
                    $res[\mktime(0,0,0,11,19,$jahr)] = 'Buss- und Bettag';
                    return $res;
                case \UF\Bundesland::SACHSEN_ANHALT:
                    $res[\mktime(0,0,0,1,6,$jahr)] = 'Heilige Drei Koenige';
                    $res[\mktime(0,0,0,10,31,$jahr)] = 'Reformationsfest';
                    return $res;
                case \UF\Bundesland::THUERINGEN:
                    $res[\mktime(0,0,0,5,22,$jahr)] = 'Fronleichnam';
                    $res[\mktime(0,0,0,10,31,$jahr)] = 'Reformationsfest';
                    return $res;
                default:
                    return $res;
            }

        }

        # </editor-fold>

    }

    # </editor-fold>

}

